﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using FotoAnotSharp.Anotator;
using FotoAnotSharp.Gate;
using System.Globalization;

namespace FotoAnotSharp
{
    /// <summary>
    /// This class completing most of GUI and contains anotated objects
    /// anotated image and compositin trees
    /// </summary>
    public partial class GateAnotaionComponent : UserControl
    {
        private Dictionary<AnotPolygon, AnotatedObject> mObjects = new Dictionary<AnotPolygon, AnotatedObject>();

        /// <summary>
        /// Gets list of anotated objects
        /// </summary>
        public IEnumerable<AnotatedObject> AnotatedObjects { get { return mObjects.Values; } }
        /// <summary>
        /// Gets annotated image
        /// </summary>
        public Image AnotatedImage { get { return anotationEditor1.Background; } }

        /// <summary>
        /// Generates composition trees
        /// </summary>
        /// <returns>Composition trees</returns>
        public IEnumerable<AnotPolygonTree> GenerateCompositionTrees()
        {
            List<AnotPolygonTree> composTree;
            AnotPolygonTree.MakeTree(anotationEditor1.Polygons, out composTree);
            return composTree;
        }

        private AnotatedObject GetObject(AnotPolygon polygon)
        {
            AnotatedObject ret;
            if (!mObjects.TryGetValue(polygon, out ret))
            {
                mObjects[polygon] = (ret = new AnotatedObject(polygon));
                ret.GateObject = mGate.Parent;
            }
            return ret;
        }

        private void RemoveObject(AnotPolygon polygon)
        {
            mObjects.Remove(polygon);
        }

        private bool mLoading = false;

        public GateAnotaionComponent()
        {
            InitializeComponent();

            anotationEditor1.PolygonSelected += new Anotator.AnotationEditor.AnotPolygonDelegate(anotationEditor1_PolygonSelected);
            anotationEditor1.PolygonCreated += new AnotationEditor.AnotPolygonDelegate(anotationEditor1_PolygonCreated);
            anotationEditor1.PolygonRemoved += new AnotationEditor.AnotPolygonDelegate(anotationEditor1_PolygonRemoved);
            anotationEditor1.PolygonMoved += new AnotationEditor.AnotPolygonDelegate(anotationEditor1_PolygonMoved);
            gatePicker1.GateObjectPicked += new GateObjectPickedDelegate(gatePicker1_GateObjectPicked);

            compositionView1.GetObjectLabel = new Func<AnotPolygon, string>((pol) => mObjects[pol].DisplayName);
            compositionView1.PolygonSelected += new CompositionView.PolygonSelectedDelegate(compositionView1_PolygonSelected);

            UpdateLabel();
        }

        void compositionView1_PolygonSelected(CompositionView sender, AnotPolygon selected)
        {
            SelectPolygon(selected);
        }

        private GraphicalObjectHiearchy mGate;

        public void LoadGate(GraphicalObjectHiearchy gate)
        {
            mGate = gate;
            gatePicker1.LoadHiearchy(gate);
        }

        void anotationEditor1_PolygonRemoved(AnotationEditor sender, AnotPolygon polygon)
        {
            RemoveObject(polygon);

            RebuildCompositionTree();
        }

        void anotationEditor1_PolygonCreated(AnotationEditor sender, AnotPolygon polygon)
        {
            GetObject(polygon);

            RebuildCompositionTree();
        }

        void anotationEditor1_PolygonMoved(AnotationEditor sender, AnotPolygon polygon)
        {
            RebuildCompositionTree();
        }

        void gatePicker1_GateObjectPicked(GatePicker sender, GraphicalObject picked)
        {
            if (mSelectedObject == null) return;

            mSelectedObject.GateObject = picked;
            UpdateLabel();
            compositionView1.ReloadLabels();
        }

        AnotatedObject mSelectedObject = null;
        void anotationEditor1_PolygonSelected(Anotator.AnotationEditor sender, Anotator.AnotPolygon selected)
        {
            SelectPolygon(selected);
        }

        void SelectPolygon(AnotPolygon selected)
        {
            if (selected == null)
            {
                if (mSelectedObject == null)
                    return;

                anotationEditor1.SelectedPolygon = null;
                compositionView1.Selected = null;
                gatePicker1.SelectedObject = null;
                mSelectedObject = null;
                UpdateLabel();
                return;
            }

            AnotatedObject newSelected = GetObject(selected);
            if (newSelected == mSelectedObject)
                return;

            mSelectedObject = newSelected;

            anotationEditor1.SelectedPolygon = selected;
            compositionView1.Selected = selected;
            gatePicker1.SelectedObject = mSelectedObject.GateObject;

            UpdateLabel();
        }

        private void UpdateLabel()
        {
            if (mSelectedObject == null)
            {
                toolStripLabelObject.Enabled = false;
                toolStripDropDownButtonObject.Enabled = false;
                toolStripDropDownButtonObject.Text = "Objekt";
            }
            else
            {
                toolStripLabelObject.Enabled = true;
                toolStripDropDownButtonObject.Enabled = true;
                toolStripDropDownButtonObject.Text = string.Format("Objekt ({0})", mSelectedObject.DisplayName);
            }
        }

        public GateAnotatedFile GetSaveFile()
        {
            GateAnotatedFile file = new GateAnotatedFile();
            file.Anotation = anotationEditor1.GetSaveFile();
            file.Objects = mObjects.Values.Select(t =>
                {
                    return new GateAnotatedFileItem()
                    {
                        GateItem = t.GateObject.Name,
                        AnotId = t.Polygon.Id,
                        Name = t.Name,
                        Labels = t.Labels.Select(s =>
                            new GateAnotatedFileItem.Label() { Info = s.Key, LabelText = s.Value }
                            ).ToList()
                    };
                }).ToList();
            return file;
        }
        public void Clear()
        {
            compositionView1.Clear();
            mObjects.Clear();
        }
        public void LoadFile(GateAnotatedFile file)
        {
            try
            {
                mLoading = true;
                Clear();

                if (file.Anotation != null)
                    anotationEditor1.LoadFile(file.Anotation);

                foreach (GateAnotatedFileItem item in file.Objects)
                {
                    AnotPolygon polygon;
                    if (!anotationEditor1.GetPolygon(item.AnotId, out polygon))
                        continue;

                    GraphicalObject grObj;
                    AnotatedObject obj = GetObject(polygon);
                    obj.Name = item.Name;
                    if (mGate.TryGetObject(item.GateItem, out grObj))
                        obj.GateObject = grObj;

                    foreach (GateAnotatedFileItem.Label label in item.Labels.Where(t => t.Info != null && !string.IsNullOrEmpty(t.LabelText)))
                    {
                        obj.AddLabel(label.Info, label.LabelText);
                    }
                }
            }
            finally { mLoading = false; }

            RebuildCompositionTree();
        }

        private void vlastnostiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (mSelectedObject == null)
                return;

            GateAnotationLabelsForm labelsForm = new GateAnotationLabelsForm(mSelectedObject);
            if (labelsForm.ShowDialog() == DialogResult.OK)
            {
                UpdateLabel();
                compositionView1.ReloadLabels();
            }
        }

        private void labelCompos_Click(object sender, EventArgs e)
        {
            RebuildCompositionTree();
        }

        void RebuildCompositionTree()
        {
            if (mLoading)
                return;

            AnotPolygon sel = compositionView1.Selected;
            compositionView1.LoadTree(GenerateCompositionTrees());
            compositionView1.Selected = sel;
        }

        public class AnotatedObject
        {
            public AnotPolygon Polygon { get; private set; }

            public string Name { get; set; }

            public string DisplayName { get { return string.IsNullOrEmpty(Name) ? GateObject.CommentOrName : Name; } }

            public AnotatedObject(AnotPolygon polygon)
            {
                Polygon = polygon;
            }

            public GraphicalObject GateObject { get; set; }

            Dictionary<CultureInfo, string> mLabels = new Dictionary<CultureInfo, string>();

            public IEnumerable<KeyValuePair<CultureInfo, string>> Labels { get { return mLabels; } }
            public void ClearLabels() { mLabels.Clear(); }
            public void AddLabel(CultureInfo key, string comment)
            { mLabels[key] = comment; }
        }
    }

}
